package service

import (
	"context"
	"errors"
	"gorm.io/gorm"
	v1 "server_go/api/v1"
	"server_go/internal/model"
	"server_go/internal/repository"
)

type ArticleService interface {
	GetArticle(ctx context.Context, id int64) (*model.Article, error)
	DeleteArticle(ctx context.Context, articleId uint, userId uint, usertype int) error
	CreateArticle(ctx context.Context, req v1.CreateArticleRequest) error
	GetArticles(ctx context.Context) ([]v1.GetArticlesResponse, error)
	GetArticlesByUserId(ctx context.Context, userId uint) ([]v1.GetArticlesByUserIdResponse, error)
	GetArticlesByTagID(ctx context.Context, tagID uint) ([]v1.GetArticlesByTagIdResponse, error)
}

func NewArticleService(
	service *Service,
	articleRepository repository.ArticleRepository,
	tagRepository repository.TagRepository,
) ArticleService {
	return &articleService{
		Service:           service,
		articleRepository: articleRepository,
		tagRepository:     tagRepository,
	}
}

type articleService struct {
	*Service
	articleRepository repository.ArticleRepository
	tagRepository     repository.TagRepository
}

func (s *articleService) GetArticle(ctx context.Context, id int64) (*model.Article, error) {
	return s.articleRepository.GetArticle(ctx, id)
}
func (s *articleService) GetTagIdByArticleID(ctx context.Context, articleId uint) ([]uint, error) {
	tagId, err := s.articleRepository.GetTagIdByArticleID(ctx, articleId)
	if err != nil {
		return nil, err
	}
	return tagId, nil
}
func (s *articleService) DeleteArticle(ctx context.Context, articleId uint, userId uint, usertype int) error {
	if usertype != 1 {
		article, err := s.articleRepository.GetArticleByID(ctx, articleId)
		if err != nil {
			return err
		}
		if article == nil {
			return v1.ErrNotFound
		}
		err = s.articleRepository.DeleteArticleByID(ctx, articleId)
		if err != nil {
			return err
		}
	}
	return nil
}
func (s *articleService) CreateArticle(ctx context.Context, req v1.CreateArticleRequest) error {
	for _, tag := range req.Tags {
		_, err := s.tagRepository.GetTagById(ctx, tag)
		if err != nil {
			return v1.ErrNotFound
		}
	}
	_, err, articleId := s.articleRepository.CreateArticle(ctx, req)
	if err != nil {
		return err
	}
	for _, tag := range req.Tags {
		_, err := s.articleRepository.CreateArticleTag(ctx, tag, articleId)
		if err != nil {
			return err
		}

	}
	return err
}

func (s *articleService) GetArticles(ctx context.Context) ([]v1.GetArticlesResponse, error) {
	articles, err := s.articleRepository.GetArticles(ctx)
	if err != nil {
		return nil, err
	}

	var res []v1.GetArticlesResponse
	for _, article := range *articles {

		tagIDs, err := s.GetTagIdByArticleID(ctx, article.ID)
		if err != nil {
			return nil, err
		}

		tags, err := s.articleRepository.GetTagsByIDs(ctx, tagIDs)
		if err != nil {
			return nil, err
		}

		var tagResponses []v1.GetTagsResponse
		for _, tag := range tags {
			tagResponses = append(tagResponses, v1.GetTagsResponse{
				ID:   tag.ID,
				Name: tag.Name,
			})
		}

		user, err := s.articleRepository.GetUserById(ctx, article.UserID)
		if err != nil {
			return nil, err
		}

		res = append(res, v1.GetArticlesResponse{
			Title:     article.Title,
			Content:   article.Content,
			UserId:    article.UserID,
			Tags:      tagResponses,
			UserName:  user.Name, // 这里填充用户名
			ArticleId: article.ID,
		})
	}

	return res, nil
}

func (s *articleService) GetArticlesByUserId(ctx context.Context, userId uint) ([]v1.GetArticlesByUserIdResponse, error) {

	articles, err := s.articleRepository.QueryUserByUserId(ctx, userId)
	if err != nil {
		return nil, err
	}

	user, err := s.articleRepository.GetUserById(ctx, userId)
	if err != nil {
		return nil, err
	}
	var res []v1.GetArticlesByUserIdResponse

	for _, article := range articles {

		tagIDs, err := s.GetTagIdByArticleID(ctx, article.ID)
		if err != nil {
			return nil, err
		}

		tags, err := s.articleRepository.GetTagsByIDs(ctx, tagIDs)
		if err != nil {
			return nil, err
		}

		var tagResponses []v1.GetTagsResponse
		for _, tag := range tags {
			tagResponses = append(tagResponses, v1.GetTagsResponse{
				ID:   tag.ID,
				Name: tag.Name,
			})
		}

		res = append(res, v1.GetArticlesByUserIdResponse{
			Title:     article.Title,
			Content:   article.Content,
			UserId:    article.UserID,
			Tags:      tagResponses,
			UserName:  user.Name,
			ArticleId: article.ID,
		})
	}

	return res, nil
}

func (s *articleService) GetArticlesByTagID(ctx context.Context, tagID uint) ([]v1.GetArticlesByTagIdResponse, error) {
	articleIDs, err := s.articleRepository.GetArticleIDsByTagID(ctx, tagID)
	if err != nil {
		return nil, err
	}
	if len(articleIDs) == 0 {
		return []v1.GetArticlesByTagIdResponse{}, nil
	}

	var res []v1.GetArticlesByTagIdResponse

	for _, articleID := range articleIDs {
		article, err := s.articleRepository.GetArticleByID(ctx, articleID)
		if err != nil {

			if errors.Is(err, gorm.ErrRecordNotFound) {
				continue
			}

			return nil, err
		}
		if article == nil {
			continue
		}

		tagIDs, err := s.articleRepository.GetTagIdByArticleID(ctx, article.ID)
		if err != nil {
			return nil, err
		}

		tags, err := s.articleRepository.GetTagsByIDs(ctx, tagIDs)
		if err != nil {
			return nil, err
		}

		var tagResponses []v1.GetTagsResponse
		for _, tag := range tags {
			tagResponses = append(tagResponses, v1.GetTagsResponse{
				ID:   tag.ID,
				Name: tag.Name,
			})
		}

		user, err := s.articleRepository.GetUserById(ctx, article.UserID)
		if err != nil {

			if errors.Is(err, gorm.ErrRecordNotFound) {
				continue
			}
			return nil, err
		}
		if user == nil {
			continue
		}

		res = append(res, v1.GetArticlesByTagIdResponse{
			Title:     article.Title,
			Content:   article.Content,
			UserId:    article.UserID,
			Tags:      tagResponses,
			UserName:  user.Name,
			ArticleId: article.ID,
		})
	}

	return res, nil
}
